package xyz.wanhongtao.smtpclient.service;

import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import xyz.wanhongtao.smtpclient.object.form.SendMailForm;
import xyz.wanhongtao.smtpclient.object.properties.SmtpConf;
import xyz.wanhongtao.smtpclient.object.vo.SendMailRes;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author wanghongtao <wanghongtao05@kuaishou.com>
 * Created on 2023-07-03
 */
@AllArgsConstructor
@Service
public class SmtpService {
    /**
     * 前端UI
     * 协议实现
     * 流程分析（流程图）
     * 资料搜集（smtp原理）
     * 整体框架
     */

    private final SmtpConf smtpConf;
    public SendMailRes sendMessage(SendMailForm sendMailForm) {
        StringBuilder message = new StringBuilder();
        try {
            // 建立TCP连接
            Socket socket = new Socket(smtpConf.getHost(), smtpConf.getPort());

            // 获取输入输出流
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            OutputStream outputStream = socket.getOutputStream();
            // 读取服务器的欢迎消息
            message.append("connect\n");
            printRes(reader, message);
            // 发送HELO命令
            message.append("Client command: HELO smtp.qq.com\n");
            sendCommand(outputStream, "HELO smtp.qq.com");
            printRes(reader, message);

            // 发送身份验证命令（例如使用用户名和密码进行身份验证）
            message.append("Client command: AUTH LOGIN\n");
            sendCommand(outputStream, "AUTH LOGIN");
            printRes(reader, message);

            // 发送Base64编码的用户名
            String usernameEncode = Base64.getEncoder().encodeToString(smtpConf.getUsername().getBytes(StandardCharsets.UTF_8));
            message.append("Client Auth command: username after encode\n");
            sendCommand(outputStream, usernameEncode);
            printRes(reader, message);

            // 发送Base64编码的密码
            String passwordEncode = Base64.getEncoder().encodeToString(smtpConf.getPassword().getBytes(StandardCharsets.UTF_8));
            message.append("Client Auth command: password after encode\n");
            sendCommand(outputStream, passwordEncode);
            printRes(reader, message);

            // 发送发件人信息
            message.append("Client command: " + "MAIL FROM: <").append(sendMailForm.getSender()).append(">").append("\n");
            sendCommand(outputStream, "MAIL FROM: <" + sendMailForm.getSender() + ">");
            printRes(reader, message);

            // 发送收件人信息
            message.append("RCPT TO: <").append(sendMailForm.getReceiver()).append(">");
            sendCommand(outputStream, "RCPT TO: <" + sendMailForm.getReceiver() + ">");
            printRes(reader, message);

            // 发送邮件内容
            message.append("DATA\n");
            sendCommand(outputStream, "DATA");
            printRes(reader, message);

            // 发送邮件头
            String emailHead = "From: " + sendMailForm.getSender() + "\r\n"
                    + "To: " + sendMailForm.getReceiver() + "\r\n"
                    + "Subject: "+ sendMailForm.getTitle() + "\r\n"
                    + "MIME-Version: 1.0" + "\r\n"
                    + "Content-Type: multipart/mixed; boundary=boundary" + "\r\n"
                    + "\r\n";
            sendCommand(outputStream, emailHead);

            //发送邮件内容
            String emailContent = "--boundary" + "\r\n"
                    + "Content-Type: text/plain" + "\r\n"
                    + "\r\n"
                    + sendMailForm.getMessage() + "\r\n"
                    + "\r\n";
            sendCommand(outputStream, emailContent);

            if (sendMailForm.getMultipartFile() != null) {
                //发送附件
                String file = "--boundary" + "\r\n"
                        + "Content-Type: application/octet-stream" + "\r\n"
                        + "Content-Disposition: attachment; filename=\"" + sendMailForm.getMultipartFile().getOriginalFilename() + "\"";
                sendCommand(outputStream, file);

                InputStream fileInputStream = sendMailForm.getMultipartFile().getInputStream();
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                fileInputStream.close();
            }
            sendCommand(outputStream, "\r\n");
            //结束发送
            sendCommand(outputStream, "--boundary--\r\n");
            sendCommand(outputStream, ".");
            printRes(reader, message);
            // 关闭连接
            sendCommand(outputStream, "QUIT");
            printRes(reader, message);
            SendMailRes sendMailRes = new SendMailRes(message.toString());
            socket.close();
            return sendMailRes;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new SendMailRes("发送失败");
    }

    private static void sendCommand(OutputStream outputStream, String command) throws IOException {
        System.out.println("Client command: " + command);
        outputStream.write((command + "\r\n").getBytes());
        outputStream.flush();
    }

    private static void printRes(BufferedReader reader, StringBuilder message) throws IOException {
        String res;
        while ((res = reader.readLine()) != null) {
            System.out.println("Server response: " + res);
            message.append("Server response: ").append(res).append("\n");
            if (res.charAt(3) == ' ') break;
        }
    }

}
